package de.fhd.pms.dao;

import java.sql.SQLException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


import de.fhd.pms.dto.AutoDTO;
import de.fhd.pms.dto.FahrtDTO;
import de.fhd.pms.model.Auto;
import de.fhd.pms.model.Fahrt;
import de.fhd.pms.model.Kunde;
import de.fhd.pms.model.Station;

/**
 * The Data access class for {@link Auto} objects. DAO encapsulates all accesses 
 * to the data source, including construction and dismantling of the connection.
 * All Interaction with the database regarding the entity bean {@link Auto} 
 * should be handled by this class! Its tasks:
 * <ul>
 * <li>set new objects of the class</li>
 * <li>modify or delete an object of the class</li>
 * <li>deliver all objects of the class</li>
 * <li>further functions in context to the class objects</li>
 * </ul>
 * 
 * @author Fischer, Neetzel & Six
 */
public class AutoDao extends HibernateDaoSupport {
	private FahrtDao fahrtDao;

	public void setFahrtDao(FahrtDao fahrtDao) {
		this.fahrtDao = fahrtDao;
	}
	
	//Diese Methode zu Testzwecken für JUNIT-Testing erstellt!
	/**
	 * Creates a new {@link Auto} and saves it in the DB.
	 * @param marke
	 */
	public void create(String marke) {
		Auto a = new Auto(marke);
		save(a);
	}

	/**
	 * Returns a single {@link Auto} object by its primary DB key
	 * 
	 * @param id
	 *            the primary key of {@link Auto}
	 * @return a single {@link Auto}
	 */
	public Auto findById(int id) {
		HibernateTemplate template = getHibernateTemplate();
		return (Auto) template.get(Auto.class, id);
	}

	/**
	 * Returns all {@link Auto} objects from the DB
	 * 
	 * @return a list of {@link Auto} objects
	 * @see Auto
	 */
	public List<Auto> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		return template.loadAll(Auto.class);
	}

	/**
	 * Saves {@link Auto} object specified by the parameter in the DB
	 * 
	 * @param auto
	 *            is the object that'll be saved in the DB
	 */
	//Original
	public Auto save(Auto auto) {
		HibernateTemplate template = getHibernateTemplate();
		template.saveOrUpdate(auto);
		return auto;
	}
//	VERSUCH
//	public void save(int stationId) {
//		HibernateTemplate template = getHibernateTemplate();
//		Station station = (Station) template.get(Station.class, stationId);
//		Auto auto = new Auto();
//		auto.setStation(station);
//		template.saveOrUpdate(auto);
//	}

	/**
	 * Returns the list of Auto objects which are currently not on a trip. 
	 * The method works as follows:
	 * <ul>
	 * <li>An HQL query is specified and stored in a String variable</li>
	 * <li>Retrieve all Auto objects from the DB</li>
	 * <li>Create an empty list for the results and empty Auto objects</li>
	 * </ul>
	 * 
	 * @return a List of Auto
	 */
//	ORIGINAL
	@SuppressWarnings("unchecked")
	public List<Auto> findFreie() {
		HibernateTemplate template = getHibernateTemplate();
		List<Fahrt> aktuelleFahrten = template
				.find("from Fahrt f where f.ankunft is null");
		List<Auto> alle = template.loadAll(Auto.class);
		List<Auto> result = new LinkedList<Auto>();
		List<Auto> belegteAutos = new LinkedList<Auto>();
		for (Fahrt fahrt : aktuelleFahrten) {
			belegteAutos.add(fahrt.getAuto());
		}
		for (Auto auto : alle) {
			if (!belegteAutos.contains(auto)) {
				result.add(auto);
			}
		}
		return result;
	}

	/**
	 * Deletes the specified {@link Auto} object from the DB
	 * 
	 * @param auto
	 *            the object to be deleted
	 * @throws AutoDeleteException
	 *             if the specified {@link Auto} is included in a {@link Fahrt}
	 */
//	EXCEPTION VERSUCH
//	public void delete(Auto auto) throws AutoDeleteException {
//		HibernateTemplate template = getHibernateTemplate();
//		Set<Fahrt> fahrtenVonAuto = fahrtDao.findByAuto(auto);
//		 if (fahrtenVonAuto.size() == 0) {
//		 template.delete(auto);
//		 } else {
//		 throw new AutoDeleteException();
//		 
//		 
//		 }
//
//	}
	
	

	
//	ORIGINAL
	public void delete(Auto auto) {
		HibernateTemplate template = getHibernateTemplate();
		template.delete(auto);
	}

//	neue Methode für AutoDeleteException! Phil
//	@SuppressWarnings("unchecked")
//	public Set<Auto> findByStation(Station station) {
//		Session hibernateSession = getSession();
//		Criteria crit = hibernateSession.createCriteria(Auto.class);
//		crit.add(Restrictions.eq("station", station));
//		List<Auto> tmp = crit.list();
//		Set<Auto> result = new HashSet<Auto>();
//		for (Auto a : tmp) {
//			result.add(a);
//		}
//		return result;
//	}

	
	
	private Set<AutoDTO> createDtoSet(List<Auto> autos) {
		Set<AutoDTO> results = new TreeSet<AutoDTO>();
		for (Auto a : autos) {
			
			results.add(new AutoDTO(a.getId(),a.getCreated(),a.getBaujahr(), a.getFarbe(), a.getKennzeichen(), a.getKm(), a.getMarke(),  a.getModell(), a.getTarif(), a.getStation().getStrasse()));
		}
		return results;
	}
	
	
	
	 @SuppressWarnings({ "unchecked", "rawtypes" })
	 public Set<AutoDTO> findAllDTO() {
	 HibernateTemplate template = getHibernateTemplate();
	 return (Set<AutoDTO>) template.execute(new HibernateCallback() {
	 @Override
	 public Object doInHibernate(Session session)
	 throws HibernateException, SQLException {
	 Criteria criteria = session.createCriteria(Auto.class);
	 criteria.add(Restrictions.isNotNull("station"));
	 List<Auto> alleAutos = criteria.list();
	 return createDtoSet(alleAutos);
	 }
	 });
	 }
}